package cn.uncode.baas.server.internal.module.data;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import cn.uncode.dal.descriptor.QueryResult;
import cn.uncode.baas.server.acl.TableAcl;
import cn.uncode.baas.server.cache.SystemCache;
import cn.uncode.baas.server.dto.RestTable;
import cn.uncode.baas.server.exception.AuthorizationException;
import cn.uncode.baas.server.exception.ValidateException;
import cn.uncode.baas.server.internal.context.RestContextManager;
import cn.uncode.baas.server.internal.message.Messages;
import cn.uncode.baas.server.service.IGenericService;
import cn.uncode.baas.server.utils.AccessTokenUtils;
import cn.uncode.baas.server.utils.DataUtils;
import cn.uncode.baas.server.utils.WatchUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DataSQLModule implements IDataModule {

    @Autowired
    IGenericService genericService;

    public List<Map<String, Object>> find(Object param) throws ValidateException {
        WatchUtils.lap("sql-module-find-start");
        DataParamResolve dataParam = new DataParamResolve(DataUtils.convert2Map(param));
        List<String> failFields = checkPermission(dataParam, TableAcl.READ);
        QueryResult result = genericService.selectByCriteria(dataParam.getFields(), dataParam.getParams(),
                dataParam.getTable(), dataParam.getSeconds(), dataParam.getDatabase());
        WatchUtils.lap("sql-module-find-end");
        return result.getList(failFields);
    }

    public Map<String, Object> findOne(Object param) throws ValidateException {
        WatchUtils.lap("sql-module-find-one-start");
        DataParamResolve dataParam = new DataParamResolve(DataUtils.convert2Map(param));
        List<String> failFields = checkPermission(dataParam, TableAcl.READ);
        QueryResult result = genericService.selectByPrimaryKey(dataParam.getFields(), dataParam.getId(),
                dataParam.getTable(), dataParam.getSeconds(), dataParam.getDatabase());
        WatchUtils.lap("sql-module-find-one-end");
        return result.get(failFields);
    }

    public int update(Object param) throws ValidateException {
        WatchUtils.lap("sql-module-update-start");
        DataParamResolve dataParam = new DataParamResolve(DataUtils.convert2Map(param));
        List<String> failFields = checkPermission(dataParam, TableAcl.UPDATE);
        int result = genericService.updateByPrimaryKey(dataParam.getId(), dataParam.getParams(failFields),
                dataParam.getTable(), dataParam.getDatabase());
        WatchUtils.lap("sql-module-update-end");
        return result;
    }

    public int remove(Object param) throws ValidateException {
        WatchUtils.lap("sql-module-remove-start");
        DataParamResolve dataParam = new DataParamResolve(DataUtils.convert2Map(param));
        checkPermission(dataParam, TableAcl.REMOVE);
        int result = genericService
                .deleteByPrimaryKey(dataParam.getId(), dataParam.getTable(), dataParam.getDatabase());
        WatchUtils.lap("sql-module-remove-end");
        return result;
    }

    public Object insert(Object param) throws ValidateException {
        WatchUtils.lap("sql-module-insert-start");
        DataParamResolve dataParam = new DataParamResolve(DataUtils.convert2Map(param));
        List<String> failFields = checkPermission(dataParam, TableAcl.INSERT);
        Object result = genericService.insert(dataParam.getParams(failFields), dataParam.getTable(),
                dataParam.getDatabase());
        WatchUtils.lap("sql-module-find-end");
        return result;
    }

    @Override
    public int count(Object param) throws ValidateException {
        WatchUtils.lap("sql-module-count-start");
        DataParamResolve dataParam = new DataParamResolve(DataUtils.convert2Map(param));
        checkPermission(dataParam, TableAcl.READ);
        int result = genericService.countByCriteria(dataParam.getParams(), dataParam.getTable(),
                dataParam.getSeconds(), dataParam.getDatabase());
        WatchUtils.lap("sql-module-count-end");
        return result;
    }

    /**
     * @param dataParam
     * @param option
     * @throws ValidateException
     */
    private List<String> checkPermission(DataParamResolve dataParam, String option) throws AuthorizationException,
            ValidateException {
        if (StringUtils.isEmpty(dataParam.getTable())) {
            throw new ValidateException(Messages.getString("RuntimeError.12"));
        }
        RestTable table = SystemCache.getRestTable(RestContextManager.getContext().getBucket(), dataParam.getTable());
        return AccessTokenUtils.checkPermissions(table, option);
    }

}
